package items;

import be.kuleuven.cs.som.annotate.Basic;
import roborally.EnergyAmount;
import roborally.EnergyUnit;
import elements.IEnergyHolder;
import elements.Robot;
/**
 * @invar	| this.isLegalEnergy(this.getEnergy())
 * 
 * @version	3.0
 * @author 	Lies Tambeur 	r0264469	2Bcwsbbh
 * @author	Eline Vanrykel	r0264543	2Bcwselt
 *
 */
public class RepairKit extends Item implements IEnergyHolder{

	private EnergyAmount energy;
	/**
	 * @invar	|  MAX_ENERGY.getAmount() > 0
	 */
	private static final EnergyAmount MAX_ENERGY = new EnergyAmount(Double.MAX_VALUE,EnergyUnit.WATTSECONDS);
	
	/**
	 * @param weight
	 * @param energy
	 * @effect	| super(weight)
	 * @effect	| this.setEnergy( minimum( energy, RepairKit.getMaxEnergy() ) )
	 */
	public RepairKit(int weight, EnergyAmount energy) {
		super(weight);
		if(this.isLegalEnergy(energy)){
			this.setEnergy(energy);
		}
		else{
			this.setEnergy(RepairKit.getMaxEnergy());
		}
	}
	
	/**
	 * @effect	|this(500, new EnergyAmount(500,EnergyUnit.WATTSECONDS))
	 */
	public RepairKit(){
		this(500,new EnergyAmount(500,EnergyUnit.WATTSECONDS));
	}

	/**
	 * @effect	| this.recharge( minimum( this.getEnergy().addAndReturn(new EnergyAmount(500,EnergyUnit.WATTSECONDS)) , 
	 * 			|		RepairKit.getMaxEnergy() ) )
	 */
	@Override
	public void hit() {
		EnergyAmount amount = this.getEnergy().addAndReturn(new EnergyAmount(500,EnergyUnit.WATTSECONDS));
		if(!amount.isSmallerThan(getMaxEnergy())){
			amount = getMaxEnergy();
		}
		this.recharge(amount);
	}
	
	/**
	 *@effect	| robot.increaseMaxEnergy( (minimum( this.getEnergy() , (Robot.getMaxMaxEnergy().subtractAndReturn(robot.getMaxEnergy())).multiplyAndReturn(2) ) ).divideAndReturnr(2) )
	 *@effect	| this.setEnergy( minimum( this.getEnergy() , (Robot.getMaxMaxEnergy().subtractAndReturn(robot.getMaxEnergy())).multiplyAndReturn(2) ) )
	 */
	@Override
	public void used(Robot robot) {
		EnergyAmount amount = new EnergyAmount();
		if(this.getEnergy().divideAndReturn(2).isSmallerThan(Robot.getMaxMaxEnergy().subtractAndReturn(robot.getMaxEnergy()))){
			amount = this.getEnergy();
		}
		else{
			amount = new EnergyAmount((Robot.getMaxMaxEnergy().subtractAndReturn(robot.getMaxEnergy())).
					toEnergyUnit(EnergyUnit.WATTSECONDS).getAmount()*2,EnergyUnit.WATTSECONDS);
		}
		robot.increaseMaxEnergy(amount.divideAndReturn(2));
		this.setEnergy(this.getEnergy().subtractAndReturn(amount));
		if(this.getEnergy().isSmallerThanOrEqualTo(new EnergyAmount())){
			robot.removeItem(this);
			this.terminate();
		}
		
	}
	
	@Override
	public void setEnergy(EnergyAmount energy) {
		assert this.isLegalEnergy(energy);
		this.energy = energy;
		
	}

	/**
	 * @return	| result == this.energy
	 */
	@Override @Basic
	public EnergyAmount getEnergy() {
		return energy;
	}
	
	/**
	 * @pre		| !new EnergyAmount().isSmallerThan(amount)
	 * @effect	| this.setEnergy(this.getEnergy().addAndReturn(amount))
	 */
	@Override
	public void recharge(EnergyAmount amount) {
		assert !new EnergyAmount().isSmallerThan(amount);
		this.setEnergy(this.getEnergy().addAndReturn(amount));
	}
	
	/**
	 * @return	| result == (!energy.isSmallerThan(new EnergyAmount())) && (!RepairKit.getMaxEnergy().isSmallerThan(energy))
	 */
	@Override
	public boolean isLegalEnergy(EnergyAmount energy) {
		return (!energy.isSmallerThan(new EnergyAmount())) && (!RepairKit.getMaxEnergy().isSmallerThan(energy));
	}
	
	/**
	 * @return	| result == this.MAX_ENERGY
	 */
	public static EnergyAmount getMaxEnergy(){
		return MAX_ENERGY;
	}
	
	/**
	 * @return	| result == "REPAIR KIT with energy "+this.getEnergy()+" and weight "+this.getWeight()+"g"
	 */
	@Override
	public String toString(){
		return "REPAIR KIT with energy "+this.getEnergy()+" and weight "+this.getWeight()+"g";
	}

	/**
	 * @pre		| !new EnergyAmount().isSmallerThan(energy)
	 * @effect	| this.setEnergy(this.getEnergy().subtractAndReturn(energy))
	 */
	@Override
	public void decrease(EnergyAmount energy) {
		assert !new EnergyAmount().isSmallerThan(energy);
		this.setEnergy(this.getEnergy().subtractAndReturn(energy));
	}

}
